classdef DODemoTasks < JenkinsJob
    %DODemoTasks Create a Jenkins build job for the DO Project
    %   Create a Jenkins build job that exercises all tasks of the DO
    %   Project.
   
    
    properties
        JobDir;      % Directory in which the build job is located.
        ReportDir;   % Directory in which reports for the build job are placed.
        ProjectDir;  % Directory in which the project is located.
        ProjectName; % Name of the project.
        Project;     % Handle to the Project.
        ModelNames;  % Names of models in the DO_03_Design directory.
        
        % Service Layer instances (基于DO-178规则第4条：架构分离原则)
        ReqService;              % RequirementsManagementService - 需求管理
        ModelAnalysisService;    % ModelStaticAnalysisService - 模型静态分析
        TestService;             % TestManagementService - 测试管理（MIL/SIL/PIL）
        CodeAnalysisService;     % CodeAnalysisService - 代码分析
        CodeTestingService;      % CodeTestingService - 代码测试
    end
    
    properties
        TaskSequence = ["taskGenReqReport"
                        "taskGenSDD"
                        "taskVerifyModel2Reqs"
                        "taskCheckModelStds"
                        "taskDetectDesignErrs"
                        "taskGenSrcCode"
                        "taskVerifySrcCode2Model"
                        "taskCheckCodeStds"
                        "taskProveCodeQuality"
                        "taskVerifyObjCode2Reqs"
                        "taskGenLowLevelTests"
                        "taskVerifyObjCode2LowLevelTests"
                        "taskMergeCodeCoverage"];
    end
    
    methods
        function setupJob(this)
            % Equivalent to (TestClassSetup) of matlab.unittest.TestCase.
            this.JobDir = fileparts(mfilename('fullpath'));
            this.ReportDir = regexprep(this.JobDir, 'job$', 'reports');
            addpath(this.JobDir);
            this.clearCache();
            this.loadProject();
            this.getModelNames();
            this.initializeServices();
            
            % 切换到工作文件夹（基于DO-178规则第8条：GUI友好界面）
            fprintf('📁 切换到工作文件夹...\n');
            toWorkFolder();
            fprintf('✅ 已切换到工作文件夹: %s\n\n', pwd);
        end
        
        function setupTask(this)
            % Equivalent to (TestMethodSetup) of matlab.unittest.TestCase.
        end
        
        function cleanupTask(this)
            % Equivalent to (TestMethodTeardown) of matlab.unittest.TestCase.
        end
        
        function cleanupJob(this)
            % Equivalent to (TestClassTeardown) of matlab.unittest.TestCase.
            this.closeProject();
            this.restoreDir();
        end
    end
    
    methods % For use by setupJob.
        function clearCache(this)
            % The MATLAB Compiler Runtime (MCR) cache can cause errors with
            % Polyspace in certain installations. Delete the entire cache
            % to avoid running into this problem.
            cacheDir = fullfile(tempdir, getenv('username'));
            if exist(cacheDir, 'dir')
                rmdir(cacheDir, 's');
            end
        end
        
        function loadProject(this)
            prj = dir(fullfile(this.JobDir, '..', '..', '*.prj'));
            this.ProjectDir = prj.folder;
            this.ProjectName = prj.name;
            this.Project = matlab.project.loadProject(fullfile(this.ProjectDir, this.ProjectName));
        end
        
        function getModelNames(this)
%             designDir = ProjectPathManager.getDirPath('design root');
%             dirList = dir(designDir);
%             
%             % Ignore common, sample_model, and names that are not a folder such as ".", "..", and ".svn".
%             ignoreDir = arrayfun(@(x) (x.isdir == 0) || strcmpi(x.name, 'sample_model') || strcmpi(x.name, 'common') || contains(x.name, '.'), dirList);
%             dirList = dirList(~ignoreDir);
%             this.ModelNames = arrayfun(@(x) (x.name), dirList, 'UniformOutput', false);
            this.ModelNames = find_mdlrefs('Flight_Control');
        end
        
        function initializeServices(this)
            % 初始化所有Service Layer实例（CI环境）
            % 基于DO-178规则第4条：架构分离原则
            
            fprintf('初始化Service Layer实例（CI环境）...\n');
            
            try
                % 初始化需求管理服务
                this.ReqService = RequirementsManagementService('Environment', 'CI');
                
                % 初始化模型静态分析服务
                this.ModelAnalysisService = ModelStaticAnalysisService('Environment', 'CI');
                
                % 初始化测试管理服务（2025-11-02更新：使用TestManagementService）
                this.TestService = TestManagementService('Environment', 'CI');
                
                % 初始化代码分析服务
                this.CodeAnalysisService = CodeAnalysisService('Environment', 'CI');
                
                % 初始化代码测试服务
                this.CodeTestingService = CodeTestingService('Environment', 'CI');
                
                fprintf('✅ 所有Service Layer实例初始化完成\n\n');
                
            catch ME
                error('DODemoTasks:InitializeServicesFailed', ...
                    '初始化Service Layer失败：%s', ME.message);
            end
        end
    end
    
    methods % For use by setupTask.
    end
    
    methods % For use by cleanupTask.
    end
    
    methods % For use by cleanupJob.
        function closeProject(this)
            this.Project.close();
        end
        
        function restoreDir(this)
            cd(this.JobDir);
        end
    end
    
    methods % For use by assertion.
        function ciResult = convertServiceResultToCIResult(this, serviceResult, methodName, componentName)
            % 将Service Layer的返回结果转换为CI格式的result结构
            % 输入：
            %   serviceResult - Service返回的结果结构 {success, message, reportPath, details}
            %   methodName - 方法名称（如'checkModelStds'）
            %   componentName - 组件名称（通常是模型名）
            % 输出：
            %   ciResult - CI格式的result结构 {Message, Method, Component, NumTotal, NumPass, NumWarn, NumFail, Outcome, Results}
            
            ciResult = struct();
            ciResult.Message = serviceResult.message;
            ciResult.Method = methodName;
            ciResult.Component = componentName;
            
            % 从serviceResult.details中提取统计信息
            if isfield(serviceResult, 'details') && isstruct(serviceResult.details)
                details = serviceResult.details;
                
                % 提取NumTotal, NumPass, NumWarn, NumFail
                if isfield(details, 'NumTotal')
                    ciResult.NumTotal = details.NumTotal;
                else
                    ciResult.NumTotal = 0;
                end
                
                if isfield(details, 'NumPass')
                    ciResult.NumPass = details.NumPass;
                else
                    ciResult.NumPass = 0;
                end
                
                if isfield(details, 'NumWarn')
                    ciResult.NumWarn = details.NumWarn;
                else
                    ciResult.NumWarn = 0;
                end
                
                if isfield(details, 'NumFail')
                    ciResult.NumFail = details.NumFail;
                else
                    ciResult.NumFail = 0;
                end
                
                % 提取Outcome
                if isfield(details, 'Outcome')
                    ciResult.Outcome = details.Outcome;
                else
                    % 根据success标志推断Outcome
                    if serviceResult.success
                        ciResult.Outcome = 1;  % PASS
                    else
                        ciResult.Outcome = -1;  % FAIL
                    end
                end
                
                % 提取详细结果
                if isfield(details, 'Results')
                    ciResult.Results = details.Results;
                else
                    ciResult.Results = details;
                end
            else
                % 如果没有details，使用默认值
                ciResult.NumTotal = 0;
                ciResult.NumPass = 0;
                ciResult.NumWarn = 0;
                ciResult.NumFail = 0;
                ciResult.Results = [];
                
                % 根据success标志设置Outcome
                if serviceResult.success
                    ciResult.Outcome = 1;  % PASS
                else
                    ciResult.Outcome = -1;  % FAIL
                end
            end
        end
        
        function [newOutcome, newMsg, newCounter] = verifyOutcome(this, outcome, msg, lastMsg, lastOutcome, lastCounter)
            newOutcome = min(outcome, lastOutcome);
            if outcome == 1
                newCounter = lastCounter;
                newMsg = lastMsg;
            else
                % Append failure or warning to exception.
                newCounter = lastCounter + 1;
                if outcome == 0
                    tag = ['(', num2str(newCounter), ') WARNING: '];
                else
                    tag = ['(', num2str(newCounter), ') FAILURE: '];
                end
                if isempty(lastMsg)
                    newMsg = [tag, msg];
                else
                    newMsg = sprintf([lastMsg, '\n', tag, msg]);
                end
            end
        end
        
        function [newOutcome, newMsg, newCounter] = verifyFile(this, file, msg, lastMsg, lastOutcome, lastCounter)
            if exist(file, 'file')
                newOutcome = lastOutcome;
                newCounter = lastCounter;
                newMsg = lastMsg;
            else
                newOutcome = -1;
                % Append failure or warning to exception.
                newCounter = lastCounter + 1;
                tag = ['(', num2str(newCounter), ') FAILURE: '];
                if isempty(lastMsg)
                    newMsg = [tag, msg];
                else
                    newMsg = sprintf([lastMsg, '\n', tag, msg]);
                end
            end
        end
    end
    
    methods % For general use.
        function result = isTopModel(this, model)
            % List all top-level models in the cell array below. Note that
            % a top-level model must not be referenced by another design
            % model. However, it may appear as a referenced model in a test
            % harness.
            allTopModels = {'Flight_Control'};
            result = any(strcmpi(allTopModels, model));
        end
    end
    
    methods % Equivalent to (Test) of matlab.unittest.TestCase.
        function taskGenReqReport(this)
            % This test point checks if Requirements Reports generated from
            % requirement sets are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用RequirementsManagementService
            
            % NOTE: Requirements Reports are .docx files prior to R2020a.
            % They are .pdf files starting in R2020a.
            if verLessThan('matlab', '9.8')
                fileExt = 'docx';
            else
                fileExt = 'pdf';
            end
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Requirements Reports from requirement
                % sets in the project using RequirementsManagementService.
                reqSets = dir(fullfile(this.ProjectDir, 'DO_02_Requirements', 'specification', '**', '*.slreqx'));
                for i = 1:numel(reqSets)
                    [~, reqSetName] = fileparts(reqSets(i).name);
                    slreqxPath = fullfile(reqSets(i).folder, reqSets(i).name);
                    
                    % 使用RequirementsManagementService生成报告
                    % 第二个参数是authorNames（可选），不是outputPath
                    % genReqReport会自动确定输出路径到documents目录
                    result = this.ReqService.generateReport(slreqxPath, []);
                    
                    % 验证报告文件
                    % genReqReport会自动将报告生成到documents子目录
                    outputPath = fullfile(this.ProjectDir, 'DO_02_Requirements', 'specification', 'documents');
                    file = fullfile(outputPath, [reqSetName, '_ReqReport.', fileExt]);
                    msg = ['Requirements Report not created: ', reqSetName, '_ReqReport.', fileExt, '.'];
                    [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                end
                
                % Capture task execution outcome.
                this.TaskOutcomes('taskGenReqReport') = outcome;
                this.TaskExceptions('taskGenReqReport') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskGenSDD(this)
            % This test point checks if SDD Reports generated from models
            % are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用ModelStaticAnalysisService
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of SDD Reports from models in the
                % project using ModelStaticAnalysisService.
                for i = 1:numel(this.ModelNames)
                    % 使用ModelStaticAnalysisService生成SDD报告
                    result = this.ModelAnalysisService.generateSDD(this.ModelNames{i}, []);
                    
                    % 验证报告文件 - 使用 getRptPath 统一获取路径
                    file = getRptPath('SDD report', this.ModelNames{i});
                    msg = ['SDD Report not created: ', file];
                    [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                end
                
                % Capture task execution outcome.
                this.TaskOutcomes('taskGenSDD') = outcome;
                this.TaskExceptions('taskGenSDD') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskVerifyModel2Reqs(this)
            % This test point checks if Simulink Test and Model Coverage
            % Reports generated from models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用TestManagementService（2025-11-02更新）
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Simulink Test and Model Coverage
                % Reports (for HLR Simulation Tests) from models using TestManagementService.
                title = 'HLR Simulation Tests';
                headers = {'Model Name', 'Num Pass', 'Num Warn', 'Num Fail', 'Outcome'};
                data = {};
                for i = 1:numel(this.ModelNames)
                    if exist(fullfile(ProjectPathManager.getDirPath('HLR test cases', this.ModelNames{i}), [ProjectNamingManager.getNameStr('HLR test cases', this.ModelNames{i}), '.mldatx']), 'file')
                        try
                            % 使用TestManagementService运行HLR MIL测试
                            % 基于2025-11-02修复：传递TreatAsTopMdl参数
                            if this.isTopModel(this.ModelNames{i})
                                serviceResult = this.TestService.runTest(this.ModelNames{i}, 'HLR', 'MIL', ...
                                    'TreatAsTopMdl', true, 'Author', 'CI');
                            else
                                serviceResult = this.TestService.runTest(this.ModelNames{i}, 'HLR', 'MIL', ...
                                    'Author', 'CI');
                            end
                            
                            % 转换Service结果为CI结果
                            res = this.convertServiceResultToCIResult(serviceResult, 'verifyModel2Reqs', this.ModelNames{i});
                            
                            data(i,:) = {this.ModelNames{i}, res.NumPass, res.NumWarn, res.NumFail, res.Outcome};
                            msg = ['One or more high-level simulation test cases failed on ', this.ModelNames{i}, '.'];
                            [outcome, exception, counter] = this.verifyOutcome(res.Outcome, msg, exception, outcome, counter);
                            
                            % 使用 getRptPath 获取报告路径
                            file = getRptPath('HLR sim report', this.ModelNames{i});
                            msg = ['Simulation Test Report not created: ', file];
                            [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                            
                            file = fullfile(ProjectPathManager.getDirPath('HLR model coverage', this.ModelNames{i}), [ProjectNamingManager.getNameStr('HLR model coverage report', this.ModelNames{i}), '.html']);
                            msg = ['Model Coverage Report not created: ', ProjectNamingManager.getNameStr('HLR model coverage report', this.ModelNames{i}), '.html.'];
                            [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                        catch ME
                            % 捕获单个模型的错误，记录但继续处理其他模型
                            data(i,:) = {this.ModelNames{i}, 0, 0, 0, -1};
                            msg = ['Test execution failed on ', this.ModelNames{i}, ': ', ME.message];
                            [outcome, exception, counter] = this.verifyOutcome(-1, msg, exception, outcome, counter);
                            fprintf('⚠️  模型 %s 测试失败: %s\n', this.ModelNames{i}, ME.message);
                        end
                    else
                        data(i,:) = {this.ModelNames{i}, [], [], [], []};
                    end
                end
                
                % Capture summary table data.
                this.TaskResults('taskVerifyModel2Reqs') = {title, headers, data};
                
                % Capture task execution outcome.
                this.TaskOutcomes('taskVerifyModel2Reqs') = outcome;
                this.TaskExceptions('taskVerifyModel2Reqs') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskCheckModelStds(this)
            % This test point checks if Model Advisor Reports generated
            % from models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用ModelStaticAnalysisService
            
            % Remove cache if it exists.
            if exist(fullfile(this.ProjectDir, 'work', 'cache', 'slprj', 'modeladvisor'), 'dir')
                rmdir(fullfile(this.ProjectDir, 'work', 'cache', 'slprj', 'modeladvisor'), 's');
            end
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Model Advisor Reports from models using ModelStaticAnalysisService.
                title = 'Modeling Standards';
                headers = {'Model Name', 'Num Pass', 'Num Warn', 'Num Fail', 'Outcome'};
                data = {};
                for i = 1:numel(this.ModelNames)
                    try
                        % 使用ModelStaticAnalysisService检查模型标准
                        serviceResult = this.ModelAnalysisService.checkStandards(this.ModelNames{i});
                        
                        % 转换Service结果为CI结果
                        res = this.convertServiceResultToCIResult(serviceResult, 'checkModelStds', this.ModelNames{i});
                        
                        data(i,:) = {this.ModelNames{i}, res.NumPass, res.NumWarn, res.NumFail, res.Outcome};
                        msg = ['One or more modeling standard violations found on ', this.ModelNames{i}, '.'];
                        [outcome, exception, counter] = this.verifyOutcome(res.Outcome, msg, exception, outcome, counter);
                        
                        file = fullfile(ProjectPathManager.getDirPath('model standards', this.ModelNames{i}), [ProjectNamingManager.getNameStr('model standards report', this.ModelNames{i}), '.html']);
                        msg = ['Model Advisor Report not created: ', ProjectNamingManager.getNameStr('model standards report', this.ModelNames{i}), '.html.'];
                        [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                    catch ME
                        % 捕获单个模型的错误，记录但继续处理其他模型
                        data(i,:) = {this.ModelNames{i}, 0, 0, 0, -1};
                        msg = ['Standards check failed on ', this.ModelNames{i}, ': ', ME.message];
                        [outcome, exception, counter] = this.verifyOutcome(-1, msg, exception, outcome, counter);
                        fprintf('⚠️  模型 %s 标准检查失败: %s\n', this.ModelNames{i}, ME.message);
                    end
                end
                
                % Capture summary table data.
                this.TaskResults('taskCheckModelStds') = {title, headers, data};
                
                % Capture execution outcome.
                this.TaskOutcomes('taskCheckModelStds') = outcome;
                this.TaskExceptions('taskCheckModelStds') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskDetectDesignErrs(this)
            % This test point checks if Design Error Detection Reports
            % generated from models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用ModelStaticAnalysisService
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Design Error Detection Reports from
                % models using ModelStaticAnalysisService.
                title = 'Design Error Detection';
                headers = {'Model Name', 'Num Pass', 'Num Warn', 'Num Fail', 'Outcome'};
                data = {};
                for i = 1:numel(this.ModelNames)
                    try
                        % 使用ModelStaticAnalysisService检测设计错误
                        serviceResult = this.ModelAnalysisService.detectDesignErrors(this.ModelNames{i}, [], []);
                        
                        % 转换Service结果为CI结果
                        res = this.convertServiceResultToCIResult(serviceResult, 'detectDesignErrs', this.ModelNames{i});
                        
                        data(i,:) = {this.ModelNames{i}, res.NumPass, res.NumWarn, res.NumFail, res.Outcome};
                        msg = ['One or more design errors found on ', this.ModelNames{i}, '.'];
                        [outcome, exception, counter] = this.verifyOutcome(res.Outcome, msg, exception, outcome, counter);
                        
                        % 使用 getRptPath 获取报告路径
                        file = getRptPath('design error detection', this.ModelNames{i});
                        msg = ['Design Error Detection Report not created: ', file];
                        [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                    catch ME
                        % 捕获单个模型的错误，记录但继续处理其他模型
                        data(i,:) = {this.ModelNames{i}, 0, 0, 0, -1};
                        msg = ['Design error detection failed on ', this.ModelNames{i}, ': ', ME.message];
                        [outcome, exception, counter] = this.verifyOutcome(-1, msg, exception, outcome, counter);
                        fprintf('⚠️  模型 %s 设计错误检测失败: %s\n', this.ModelNames{i}, ME.message);
                    end
                end
                
                % Capture summary table data.
                this.TaskResults('taskDetectDesignErrs') = {title, headers, data};
                
                % Capture execution outcome.
                this.TaskOutcomes('taskDetectDesignErrs') = outcome;
                this.TaskExceptions('taskDetectDesignErrs') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskGenSrcCode(this)
            % This test point checks if Code Generation Reports generated
            % from models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用CodeAnalysisService
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Code Generation Reports from models using CodeAnalysisService.
                for i = 1:numel(this.ModelNames)
                    % 使用CodeAnalysisService生成代码
                    if this.isTopModel(this.ModelNames{i})
                        serviceResult = this.CodeAnalysisService.generateCode(this.ModelNames{i}, 'TreatAsTopMdl');
                        file = fullfile(ProjectPathManager.getDirPath('top model code', this.ModelNames{i}), 'html', [ProjectNamingManager.getNameStr('code report', this.ModelNames{i}), '.html']);
                    else
                        serviceResult = this.CodeAnalysisService.generateCode(this.ModelNames{i});
                        file = fullfile(ProjectPathManager.getDirPath('ref model code', this.ModelNames{i}), 'html', [ProjectNamingManager.getNameStr('code report', this.ModelNames{i}), '.html']);
                    end
                    
                    msg = ['Code Generation Report not created: ', ProjectNamingManager.getNameStr('code report', this.ModelNames{i}), '.html.'];
                    [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                end
                
                % Capture execution outcome.
                this.TaskOutcomes('taskGenSrcCode') = outcome;
                this.TaskExceptions('taskGenSrcCode') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskVerifySrcCode2Model(this)
            % This test point checks if Code Inspection Reports generated
            % from models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用CodeAnalysisService
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Code Inspection Reports from models using CodeAnalysisService.
                title = 'Code Inspection';
                headers = {'Model Name', 'Num Pass', 'Num Warn', 'Num Fail', 'Outcome'};
                data = {};
                for i = 1:numel(this.ModelNames)
                    try
                        % 使用CodeAnalysisService运行Code Inspector
                        if this.isTopModel(this.ModelNames{i})
                            serviceResult = this.CodeAnalysisService.runCodeInspector(this.ModelNames{i}, 'TreatAsTopMdl');
                        else
                            serviceResult = this.CodeAnalysisService.runCodeInspector(this.ModelNames{i});
                        end
                        
                        % 转换Service结果为CI结果
                        res = this.convertServiceResultToCIResult(serviceResult, 'verifySrcCode2Model', this.ModelNames{i});
                        
                        data(i,:) = {this.ModelNames{i}, res.NumPass, res.NumWarn, res.NumFail, res.Outcome};
                        msg = ['One or more code inspection failures found on ', this.ModelNames{i}, '.'];
                        [outcome, exception, counter] = this.verifyOutcome(res.Outcome, msg, exception, outcome, counter);
                        
                        file = fullfile(ProjectPathManager.getDirPath('code review', this.ModelNames{i}), [ProjectNamingManager.getNameStr('code inspector report', this.ModelNames{i}), '.html']);
                        msg = ['Code Inspection Report not created: ', ProjectNamingManager.getNameStr('code inspector report', this.ModelNames{i}), '.html.'];
                        [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                    catch ME
                        % 捕获单个模型的错误，记录但继续处理其他模型
                        data(i,:) = {this.ModelNames{i}, 0, 0, 0, -1};
                        msg = ['Code inspection failed on ', this.ModelNames{i}, ': ', ME.message];
                        [outcome, exception, counter] = this.verifyOutcome(-1, msg, exception, outcome, counter);
                        fprintf('⚠️  模型 %s 代码检查失败: %s\n', this.ModelNames{i}, ME.message);
                    end
                end
                
                % Capture summary table data.
                this.TaskResults('taskVerifySrcCode2Model') = {title, headers, data};
                
                % Capture execution outcome.
                this.TaskOutcomes('taskVerifySrcCode2Model') = outcome;
                this.TaskExceptions('taskVerifySrcCode2Model') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskCheckCodeStds(this)
            % This test point checks if Bug Finder Reports generated from
            % models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用CodeAnalysisService
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Bug Finder Reports from models using CodeAnalysisService.
                title = 'Coding Standards';
                headers = {'Model Name', 'Num MISRA violations', 'Outcome'};
                data = {};
                for i = 1:numel(this.ModelNames)
                    try
                        % 使用CodeAnalysisService运行编码标准检查
                        if this.isTopModel(this.ModelNames{i})
                            serviceResult = this.CodeAnalysisService.runCodeStandards(this.ModelNames{i}, 'TreatAsTopMdl');
                        else
                            serviceResult = this.CodeAnalysisService.runCodeStandards(this.ModelNames{i});
                        end
                        
                        % 转换Service结果为CI结果
                        res = this.convertServiceResultToCIResult(serviceResult, 'checkCodeStds', this.ModelNames{i});
                        
                        % 从details中提取NumPurple（MISRA违规数）
                        if isfield(serviceResult, 'details') && isfield(serviceResult.details, 'NumPurple')
                            numMisra = serviceResult.details.NumPurple;
                        else
                            numMisra = 0;
                        end
                        
                        data(i,:) = {this.ModelNames{i}, numMisra, res.Outcome};
                        msg = ['One or more coding rule violations found on ', this.ModelNames{i}, '.'];
                        [outcome, exception, counter] = this.verifyOutcome(res.Outcome, msg, exception, outcome, counter);
                        
                        % 使用 getRptPath 获取报告路径
                        file = getRptPath('code standards', this.ModelNames{i});
                        msg = ['Bug Finder Report not created: ', file];
                        [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                    catch ME
                        % 捕获单个模型的错误，记录但继续处理其他模型
                        data(i,:) = {this.ModelNames{i}, 0, -1};
                        msg = ['Coding standards check failed on ', this.ModelNames{i}, ': ', ME.message];
                        [outcome, exception, counter] = this.verifyOutcome(-1, msg, exception, outcome, counter);
                        fprintf('⚠️  模型 %s 代码标准检查失败: %s\n', this.ModelNames{i}, ME.message);
                    end
                end
                
                % Capture summary table data.
                this.TaskResults('taskCheckCodeStds') = {title, headers, data};
                
                % Capture execution outcome.
                this.TaskOutcomes('taskCheckCodeStds') = outcome;
                this.TaskExceptions('taskCheckCodeStds') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskProveCodeQuality(this)
            % This test point checks if Code Prover Reports generated from
            % models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用CodeAnalysisService
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Code Prover Reports from models using CodeAnalysisService.
                title = 'Code Prover Analysis';
                headers = {'Model Name', 'Num Green', 'Num Orange', 'Num Red', 'Num Gray', 'Num MISRA violations', 'Outcome'};
                data = {};
                for i = 1:numel(this.ModelNames)
                    try
                        % 使用CodeAnalysisService运行Code Prover
                        if this.isTopModel(this.ModelNames{i})
                            serviceResult = this.CodeAnalysisService.runCodeProver(this.ModelNames{i}, 'TreatAsTopMdl', 'IncludeAllChildMdls');
                        else
                            serviceResult = this.CodeAnalysisService.runCodeProver(this.ModelNames{i}, 'IncludeAllChildMdls');
                        end
                        
                        % 转换Service结果为CI结果
                        res = this.convertServiceResultToCIResult(serviceResult, 'proveCodeQuality', this.ModelNames{i});
                        
                        % 从details中提取Code Prover特有的统计数据
                        if isfield(serviceResult, 'details')
                            numGreen = serviceResult.details.NumGreen;
                            numOrange = serviceResult.details.NumOrange;
                            numRed = serviceResult.details.NumRed;
                            numGray = serviceResult.details.NumGray;
                            numPurple = serviceResult.details.NumPurple;
                        else
                            numGreen = 0; numOrange = 0; numRed = 0; numGray = 0; numPurple = 0;
                        end
                        
                        data(i,:) = {this.ModelNames{i}, numGreen, numOrange, numRed, numGray, numPurple, res.Outcome};
                        msg = ['One or more coding defects found on ', this.ModelNames{i}, '.'];
                        [outcome, exception, counter] = this.verifyOutcome(res.Outcome, msg, exception, outcome, counter);
                        
                        % 使用 getRptPath 获取报告路径
                        file = getRptPath('code prover', this.ModelNames{i});
                        msg = ['Code Prover Report not created: ', file];
                        [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                    catch ME
                        % 捕获单个模型的错误，记录但继续处理其他模型
                        data(i,:) = {this.ModelNames{i}, 0, 0, 0, 0, 0, -1};
                        msg = ['Code prover analysis failed on ', this.ModelNames{i}, ': ', ME.message];
                        [outcome, exception, counter] = this.verifyOutcome(-1, msg, exception, outcome, counter);
                        fprintf('⚠️  模型 %s 代码验证失败: %s\n', this.ModelNames{i}, ME.message);
                    end
                end
                
                % Capture summary table data.
                this.TaskResults('taskProveCodeQuality') = {title, headers, data};
                
                % Capture execution outcome.
                this.TaskOutcomes('taskProveCodeQuality') = outcome;
                this.TaskExceptions('taskProveCodeQuality') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskVerifyObjCode2Reqs(this)
            % This test point checks if Simulink Test and Code Coverage
            % Reports generated from models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用CodeTestingService
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Simulink Test and Code Coverage
                % Reports (for HLR SIL Tests) from models using CodeTestingService.
                title = 'HLR SIL Tests';
                headers = {'Model Name', 'Num Pass', 'Num Warn', 'Num Fail', 'Outcome'};
                data = {};
                for i = 1:numel(this.ModelNames)
                    if exist(fullfile(ProjectPathManager.getDirPath('HLR test cases', this.ModelNames{i}), [ProjectNamingManager.getNameStr('HLR test cases', this.ModelNames{i}), '.mldatx']), 'file')
                        try
                            % 使用CodeTestingService验证代码对需求的符合性（SIL）
                            if this.isTopModel(this.ModelNames{i})
                                serviceResult = this.CodeTestingService.verifyAgainstRequirements(this.ModelNames{i}, 'SIL', [], 'TreatAsTopMdl', []);
                            else
                                serviceResult = this.CodeTestingService.verifyAgainstRequirements(this.ModelNames{i}, 'SIL', [], [], []);
                            end
                            
                            % 转换Service结果为CI结果
                            res = this.convertServiceResultToCIResult(serviceResult, 'verifyObjCode2Reqs', this.ModelNames{i});
                            
                            data(i,:) = {this.ModelNames{i}, res.NumPass, res.NumWarn, res.NumFail, res.Outcome};
                            msg = ['One or more high-level software-in-the-loop test cases failed on ', this.ModelNames{i}, '.'];
                            [outcome, exception, counter] = this.verifyOutcome(res.Outcome, msg, exception, outcome, counter);
                            
                            % 使用 getRptPath 获取报告路径
                            file = getRptPath('HLR SIL report', this.ModelNames{i});
                            msg = ['Simulation Test Report not created: ', file];
                            [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                            
                            file = fullfile(ProjectPathManager.getDirPath('HLR SIL coverage', this.ModelNames{i}), [ProjectNamingManager.getNameStr('HLR code coverage report', this.ModelNames{i}), '.html']);
                            msg = ['Model Coverage Report not created: ', ProjectNamingManager.getNameStr('HLR code coverage report', this.ModelNames{i}), '.html.'];
                            [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                        catch ME
                            % 捕获单个模型的错误，记录但继续处理其他模型
                            data(i,:) = {this.ModelNames{i}, 0, 0, 0, -1};
                            msg = ['SIL test execution failed on ', this.ModelNames{i}, ': ', ME.message];
                            [outcome, exception, counter] = this.verifyOutcome(-1, msg, exception, outcome, counter);
                            fprintf('⚠️  模型 %s SIL测试失败: %s\n', this.ModelNames{i}, ME.message);
                        end
                    else
                        data(i,:) = {this.ModelNames{i}, [], [], [], []};
                    end
                end
                
                % Capture summary table data.
                this.TaskResults('taskVerifyObjCode2Reqs') = {title, headers, data};
                
                % Capture execution outcome.
                this.TaskOutcomes('taskVerifyObjCode2Reqs') = outcome;
                this.TaskExceptions('taskVerifyObjCode2Reqs') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskGenLowLevelTests(this)
            % This test point checks if Test Generation Reports generated
            % from models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用TestManagementService（2025-11-02更新）
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Test Generation Reports from models using TestManagementService.
                for i = 1:numel(this.ModelNames)
                    if exist(fullfile(ProjectPathManager.getDirPath('HLR model coverage', this.ModelNames{i}), [ProjectNamingManager.getNameStr('HLR model coverage', this.ModelNames{i}), '.cvt']), 'file')
                        % 使用TestManagementService生成低级测试
                        serviceResult = this.TestService.generateLowLevelTests(this.ModelNames{i});
                        
                        % 使用 getRptPath 获取报告路径
                        file = getRptPath('test generation report', this.ModelNames{i});
                        msg = ['Test Generation Report not created: ', file];
                        [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                    end
                end
                
                % Capture execution outcome.
                this.TaskOutcomes('taskGenLowLevelTests') = outcome;
                this.TaskExceptions('taskGenLowLevelTests') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskVerifyObjCode2LowLevelTests(this)
            % This test point checks if Simulink Test and Code Coverage
            % Reports generated from models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用CodeTestingService
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Simulink Test and Code Coverage
                % Reports (for LLR SIL Tests) from models using CodeTestingService.
                title = 'LLR SIL Tests';
                headers = {'Model Name', 'Num Pass', 'Num Warn', 'Num Fail', 'Outcome'};
                data = {};
                for i = 1:numel(this.ModelNames)
                    if exist(fullfile(ProjectPathManager.getDirPath('LLR test cases', this.ModelNames{i}), [ProjectNamingManager.getNameStr('LLR test cases', this.ModelNames{i}), '.mldatx']), 'file')
                        try
                            % 使用CodeTestingService验证代码对低级测试的符合性（SIL）
                            if this.isTopModel(this.ModelNames{i})
                                serviceResult = this.CodeTestingService.verifyAgainstLowLevelTests(this.ModelNames{i}, 'SIL', [], 'TreatAsTopMdl', []);
                            else
                                serviceResult = this.CodeTestingService.verifyAgainstLowLevelTests(this.ModelNames{i}, 'SIL', [], [], []);
                            end
                            
                            % 转换Service结果为CI结果
                            res = this.convertServiceResultToCIResult(serviceResult, 'verifyObjCode2LowLevelTests', this.ModelNames{i});
                            
                            data(i,:) = {this.ModelNames{i}, res.NumPass, res.NumWarn, res.NumFail, res.Outcome};
                            msg = ['One or more low-level software-in-the-loop test cases failed on ', this.ModelNames{i}, '.'];
                            [outcome, exception, counter] = this.verifyOutcome(res.Outcome, msg, exception, outcome, counter);
                            
                            % 使用 getRptPath 获取报告路径
                            file = getRptPath('LLR SIL report', this.ModelNames{i});
                            msg = ['Simulation Test Report not created: ', file];
                            [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                            
                            file = fullfile(ProjectPathManager.getDirPath('LLR SIL coverage', this.ModelNames{i}), [ProjectNamingManager.getNameStr('LLR code coverage report', this.ModelNames{i}), '.html']);
                            msg = ['Model Coverage Report not created: ', ProjectNamingManager.getNameStr('LLR code coverage report', this.ModelNames{i}), '.html.'];
                            [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                        catch ME
                            % 捕获单个模型的错误，记录但继续处理其他模型
                            data(i,:) = {this.ModelNames{i}, 0, 0, 0, -1};
                            msg = ['Low-level SIL test execution failed on ', this.ModelNames{i}, ': ', ME.message];
                            [outcome, exception, counter] = this.verifyOutcome(-1, msg, exception, outcome, counter);
                            fprintf('⚠️  模型 %s 低级SIL测试失败: %s\n', this.ModelNames{i}, ME.message);
                        end
                    else
                        data(i,:) = {this.ModelNames{i}, [], [], [], []};
                    end
                end
                
                % Capture summary table data.
                this.TaskResults('taskVerifyObjCode2LowLevelTests') = {title, headers, data};
                
                % Capture execution outcome.
                this.TaskOutcomes('taskVerifyObjCode2LowLevelTests') = outcome;
                this.TaskExceptions('taskVerifyObjCode2LowLevelTests') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
        
        function taskMergeCodeCoverage(this)
            % This test point checks if Cumulative Code Coverage Reports
            % generated from models are successfully created by Service Layer.
            % 基于DO-178规则第4条：使用CodeTestingService
            
            outcome = 1;
            exception = '';
            counter = 0;
            try
                % Test generation of Cumulative Code Coverage Reports from
                % models using CodeTestingService.
                title = 'Cumulative Code Coverage';
                headers = {'Model Name', 'Statement', 'Decision', 'Condition', 'MCDC', 'Outcome'};
                data = {};
                for i = 1:numel(this.ModelNames)
                    if exist(fullfile(ProjectPathManager.getDirPath('HLR SIL results', this.ModelNames{i}), 'instrumented', [ProjectNamingManager.getNameStr('HLR SIL results', this.ModelNames{i}), '.mldatx']), 'file') ...
                            && exist(fullfile(ProjectPathManager.getDirPath('LLR SIL results', this.ModelNames{i}), 'instrumented', [ProjectNamingManager.getNameStr('LLR SIL results', this.ModelNames{i}), '.mldatx']), 'file')
                        try
                            % 使用CodeTestingService合并代码覆盖率
                            serviceResult = this.CodeTestingService.mergeCoverage(this.ModelNames{i}, 'SIL');
                            
                            % 转换Service结果为CI结果
                            res = this.convertServiceResultToCIResult(serviceResult, 'mergeCodeCoverage', this.ModelNames{i});
                            
                            % 从details中提取覆盖率数据
                            if isfield(serviceResult, 'details')
                                cumExecCov = serviceResult.details.CumulativeExecutionCov;
                                cumDecCov = serviceResult.details.CumulativeDecisionCov;
                                cumCondCov = serviceResult.details.CumulativeConditionCov;
                                cumMCDCCov = serviceResult.details.CumulativeMCDCCov;
                            else
                                cumExecCov = []; cumDecCov = []; cumCondCov = []; cumMCDCCov = [];
                            end
                            
                            data(i,:) = {this.ModelNames{i}, cumExecCov, cumDecCov, cumCondCov, cumMCDCCov, res.Outcome};
                            msg = ['One or more code coverage objectives not achieved on ', this.ModelNames{i}, '.'];
                            [outcome, exception, counter] = this.verifyOutcome(res.Outcome, msg, exception, outcome, counter);
                            
                            file = fullfile(ProjectPathManager.getDirPath('SIL coverage', this.ModelNames{i}), [ProjectNamingManager.getNameStr('code coverage report', this.ModelNames{i}), '.html']);
                            msg = ['Cumulative Code Coverage Report not created: ', ProjectNamingManager.getNameStr('code coverage report', this.ModelNames{i}), '.html.'];
                            [outcome, exception, counter] = this.verifyFile(file, msg, exception, outcome, counter);
                        catch ME
                            % 捕获单个模型的错误，记录但继续处理其他模型
                            data(i,:) = {this.ModelNames{i}, [], [], [], [], -1};
                            msg = ['Coverage merge failed on ', this.ModelNames{i}, ': ', ME.message];
                            [outcome, exception, counter] = this.verifyOutcome(-1, msg, exception, outcome, counter);
                            fprintf('⚠️  模型 %s 覆盖率合并失败: %s\n', this.ModelNames{i}, ME.message);
                        end
                    else
                        data(i,:) = {this.ModelNames{i}, [], [], [], [], []};
                    end
                end
                
                % Capture summary table data.
                this.TaskResults('taskMergeCodeCoverage') = {title, headers, data};
                
                % Capture execution outcome.
                this.TaskOutcomes('taskMergeCodeCoverage') = outcome;
                this.TaskExceptions('taskMergeCodeCoverage') = exception;
            catch ME
                % Throw exception if an error occurs.
                rethrow(ME);
            end
        end
    end
    
end
